package org.ft.service.auth;

import cn.hutool.crypto.SecureUtil;
import com.ft.core.exceptions.UserFriendlyException;
import com.ft.security.SecurityConstants;
import com.ft.security.model.JwtToken;
import com.ft.security.model.JwtUser;
import com.ft.security.service.IAuthService;
import com.ft.security.utils.JwtTokenUtil;
import lombok.AllArgsConstructor;
import org.ft.domain.entities.*;
import org.ft.domain.enums.UserStatus;
import org.ft.domain.repositories.ITenantBusRepository;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @copyright (C), 2015-2019, XXX有限公司
 * @fileName: AuthService
 * @author: 李阳
 * @date: 2019/7/4 23:41
 * @description: 授权鉴权相关服务
 * @history: <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
@Service
@AllArgsConstructor
public class AuthServiceImpl implements IAuthService {

    private ITenantBusRepository tenantBusRepository;
    private JwtTokenUtil jwtTokenUtil;

    @Override
    public JwtToken login(String username, String password) {
        return null;
    }

    @Override
    public Boolean logout() {
        return null;
    }

    @Override
    public JwtToken login(String username, String password, Long tenantId) {
        final UserEntity userEntity = this.tenantBusRepository.selectTenantUser(username, tenantId);

        if (null == userEntity) {
            throw new UserFriendlyException("不存在此用户");
        }
        // 验证密码
        assertPassword(userEntity.getPassword(), userEntity.getSalt(), password);
        final JwtUser jwtUser = this.loadUserByUsername(username, tenantId);
        return jwtTokenUtil.generateToken(jwtUser);
    }


    @Override
    public JwtUser loadUserByUsername(String username, Long tenantId) {
        final UserEntity userEntity = this.tenantBusRepository.selectTenantUser(username, tenantId);
        if (null != userEntity) {
            // 获取用户角色
            final List<UserRoleEntity> tenantUserRoles = tenantBusRepository.selectTenantUserRoles(userEntity.getId(), tenantId);
            final List<Long> roleIds = tenantUserRoles.stream().map(UserRoleEntity::getRoleId).collect(Collectors.toList());
            // 获取角色信息
            final List<RoleEntity> roleEntities = tenantBusRepository.selectTenantRoles(roleIds, tenantId);
            // 获取角色权限编码
            final List<RolePermissionEntity> rolePermissionEntities = tenantBusRepository.selectTenantRolePermissions(roleIds, tenantId);
            final List<Long> permissionIds = rolePermissionEntities.stream().map(RolePermissionEntity::getPermissionId).collect(Collectors.toList());
            // 获取权限信息
            final List<PermissionEntity> permissionEntities = tenantBusRepository.selectTenantPermissions(permissionIds);

            Set<String> dbAuthSet = new HashSet<>();
            if (roleEntities.size() > 0) {
                // 获取角色
                roleEntities.forEach(role -> dbAuthSet.add(SecurityConstants.ROLE + role.getRoleCode()));
                // 获取资源权限
                dbAuthSet.addAll(permissionEntities.stream().map(PermissionEntity::getPermissionCode).collect(Collectors.toSet()));
            }

            Collection<? extends GrantedAuthority> authorities
                    = AuthorityUtils.createAuthorityList(dbAuthSet.toArray(new String[0]));

            return new JwtUser(userEntity.getId(), userEntity.getCompanyId(), userEntity.getDeptId(),
                    userEntity.getTenantId(), userEntity.getUserName(), userEntity.getPassword(), userEntity.getUserType().getValue(),
                    userEntity.getStatus().equals(UserStatus.NORMAL), true, true,
                    !userEntity.getStatus().equals(UserStatus.LOCK), authorities);
        }

        return null;
    }

    private void assertPassword(String password, String salt, String inputPassword) {
        // 生成密码盐
        final String md5Password = SecureUtil.md5(inputPassword + salt);
        if (!md5Password.toUpperCase().equals(password.toUpperCase())) {
            throw new UserFriendlyException("用户名或密码错误");
        }
    }
}
